#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include <thread>

const int kListenPort = 2222;

int SetNonBlocking(int fd) {
  int flag = fcntl(fd, F_GETFL, 0);
  return fcntl(fd, F_SETFL, flag | O_NONBLOCK);
}

bool OnAccept(int epollfd, int listen_sock) {
  struct sockaddr_in peer_addr;
  memset(&peer_addr, 0, sizeof(peer_addr));
  socklen_t peer_socklen = sizeof(peer_addr);
  // 默认水平触发，只要没读完 系统就一直通知
  // 边缘触发需要用户循环accept，直到EAGAIN or EWOULDBLOCK
  int conn_sock =
      accept(listen_sock, (struct sockaddr*)&peer_addr, &peer_socklen);
  if (conn_sock < 0) {
    switch (errno) {
      case EAGAIN || EWOULDBLOCK:
        printf("accept EAGAIN or EWOULDBLOCK\n");
        break;
      default:
        printf("accept error(%d):%s\n", errno, strerror(errno));
        return false;
    }
  } else {
    printf("accept one. conn_sock:%d, peer_addr:%s, peer_port:%d\n", conn_sock,
           inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
  }

  SetNonBlocking(conn_sock);
  epoll_event event;
  event.events = EPOLLIN /*| EPOLLET */;
  event.data.fd = conn_sock;
  if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &event) < 0) {
    printf("epoll_ctl error(%d):%s\n", errno, strerror(errno));
    return false;
  }
  return true;
}

bool OnRead(int fd) {
  // 默认水平触发，只要没读完 系统就一直通知
  // 边缘触发需要用户循环read，直到EAGAIN or EWOULDBLOCK
  char buff[8];
  memset(buff, 0, sizeof(buff));
  ssize_t n = read(fd, buff, sizeof(buff) - 1);
  if (n < 0) {
    switch (errno) {
      case EAGAIN || EWOULDBLOCK:
        printf("read EAGAIN or EWOULDBLOCK\n");
        break;
      default:
        printf("read error(%d):%s\n", errno, strerror(errno));
        return false;
    }
  }
  printf("read %ld bytes:%s", n, buff);
  if (n == 0) {
    printf("client closed, there close too.\n");
    close(fd);
  } else {
    n = write(fd, buff, strlen(buff));
    printf("echo %ld bytes:%s", n, buff);
  }
  return true;
}

bool OnWrite(int fd) { return false; }

int main() {
  int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  if (listen_sock < 0) {
    printf("socket error(%d):%s\n", errno, strerror(errno));
    return 0;
  }

  printf("listen_sock:%d\n", listen_sock);
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(kListenPort);
  if (bind(listen_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
    printf("bind error(%d):%s\n", errno, strerror(errno));
    return 0;
  }

  if (listen(listen_sock, 2) < 0) {
    printf("listen error(%d):%s\n", errno, strerror(errno));
    return 0;
  }

  // epoll
  int epollfd = epoll_create1(EPOLL_CLOEXEC);
  if (epollfd < 0) {
    printf("epoll_create1 error(%d):%s\n", errno, strerror(errno));
    return 0;
  }
  printf("epollfd:%d\n", epollfd);

  epoll_event event;
  event.events = EPOLLIN;
  event.data.fd = listen_sock;
  if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &event) < 0) {
    printf("epoll_ctl error(%d):%s\n", errno, strerror(errno));
    return 0;
  }

  const int kMaxEventNum = 10;
  const int kTimeoutMs = 30 * 1000;
  epoll_event events[kMaxEventNum];
  while (1) {
    printf("start epoll_wait...\n");
    int readyn = epoll_wait(epollfd, events, kMaxEventNum, kTimeoutMs);
    if (readyn < 0) {
      printf("epoll_wait error(%d):%s\n", errno, strerror(errno));
      return 0;
    }

    // 遍历events
    for (int i = 0; i < readyn; ++i) {
      int fd = events[i].data.fd;
      if (fd == listen_sock) {  // 新连接到达
        OnAccept(epollfd, fd);
      } else {  // 已有连接I/O事件
        if (events[i].events | EPOLLIN) {
          OnRead(fd);
        }
        if (events[i].events | EPOLLOUT) {
          OnWrite(fd);
        }
      }
    }
  }

  printf("return\n");
}
